home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 189_01 / grep.c < prev    next >
Text File  |  1985-08-19  |  12KB  |  449 lines

  1. /* grep.c: attempt to get UNIX pattern-matching on a micro */
  2.  
  3. /* From DECUS C Tools package on DEC systems - for non-commercial
  4.     use only.  Modifications by Chuck Allison, April-October 1985:
  5.  
  6.         - handles quoted arguments (for embedded spaces)
  7.         - distinguishes case (ignore with -i)
  8.         - list filename only option (-l)
  9. */
  10.  
  11. #include <stdio.h>
  12. #include <makearg.h>
  13.  
  14. #define LMAX    512
  15. #define PMAX    256
  16. #define CHAR    1
  17. #define BOL     2
  18. #define EOL     3
  19. #define ANY     4
  20. #define CLASS   5
  21. #define NCLASS  6
  22. #define STAR    7
  23. #define PLUS    8
  24. #define MINUS   9
  25. #define ALPHA   10
  26. #define DIGIT   11
  27. #define NALPHA  12
  28. #define WHITE   13
  29. #define RANGE   14
  30. #define ENDPAT  15
  31. #define TRUE    1
  32. #define FALSE   0
  33.  
  34. int  cflag = FALSE,
  35.      fflag = FALSE,
  36.      lflag = FALSE,
  37.      nflag = FALSE,
  38.      vflag = FALSE,
  39.      iflag = FALSE;
  40.  
  41. char    *pp,
  42.         lbuf[LMAX],
  43.         pbuf[PMAX];
  44.  
  45. extern char *trim_fspec();
  46.  
  47. main()
  48. {
  49.    register char   *p;
  50.  
  51.    /* ..this must be first; processes args.. */
  52.    makeargv();
  53.  
  54.    if (argc <= 1)
  55.        usage("No arguments");
  56.   
  57.    while (--argc && **++argv == '-')
  58.        for (p = *argv+1; *p; ++p)
  59.            switch(tolower(*p))
  60.            {
  61.                case 'c': 
  62.                    cflag = !cflag;
  63.                    break;
  64.                case 'f':
  65.                    fflag = !fflag;
  66.                    break;
  67.                case 'l':
  68.                    lflag = !lflag;
  69.                    break;
  70.                case 'n':
  71.                    nflag = !nflag;
  72.                    break;
  73.                case 'v':
  74.                    vflag = !vflag;
  75.                    break;
  76.                case 'i':
  77.                    iflag = !iflag;
  78.                    break;
  79.                default:
  80.                    usage("Unknown flag");
  81.            }
  82.  
  83.    if (argc <= 0)
  84.       error("no pattern\n");
  85.  
  86.    compile(*argv);
  87.  
  88.    if (argc == 1)
  89.       grep("");
  90.    else
  91.    {
  92.       /* ..check file switch.. */
  93.       if (argc > 2)
  94.           fflag = !fflag;
  95.  
  96.        while (*++argv)
  97.           if (freopen(*argv,"r",stdin) != NULL)
  98.               grep(*argv);
  99.           else
  100.               fprintf(stderr,"can't open %s\n",*argv);
  101.    }
  102. }
  103.  
  104.  
  105. usage(s)
  106. char *s;
  107. {
  108.    fprintf(stderr, "grep: %s\n", s);
  109.    fprintf(stderr,
  110.       "Usage: grep [-cfilnv] pattern [file ...]\n");
  111.    exit(1);
  112. }
  113.  
  114.  
  115. compile(source)
  116. char *source;
  117. /* ..Compile the pattern into global pbuf[].. */
  118. {
  119.    register char  *s;         /* Source string pointer     */
  120.    register char  *lp;        /* Last pattern pointer      */
  121.    register int   c;          /* Current character         */
  122.    int            o;          /* Temp                      */
  123.    char           *spp;       /* Save beginning of pattern */
  124.    char           *cclass();  /* Compile class routine     */
  125.  
  126.    s = source;
  127.    pp = pbuf;
  128.  
  129.    while (c = *s++)
  130.    {
  131.       /* ..STAR, PLUS and MINUS are special.. */
  132.       if (c == '*' || c == '+' || c == '-')
  133.       {
  134.          if ( pp == pbuf ||
  135.               (o=pp[-1]) == BOL ||
  136.               o == EOL ||
  137.               o == STAR ||
  138.               o == PLUS ||
  139.               o == MINUS
  140.             )
  141.             badpat("Illegal occurrance op.", source, s);
  142.          store(ENDPAT);
  143.          store(ENDPAT);
  144.          spp = pp;               /* Save pattern end     */
  145.          while (--pp > lp)       /* Move pattern down    */
  146.             *pp = pp[-1];        /* one byte             */
  147.          *pp =   (c == '*') ? STAR :
  148.             (c == '-') ? MINUS : PLUS;
  149.          pp = spp;               /* Restore pattern end  */
  150.          continue;
  151.       }
  152.  
  153.       /* ..All the rest.. */
  154.       lp = pp;         /* ..Remember start.. */
  155.       switch(c)
  156.       {
  157.           case '^':
  158.              store(BOL);
  159.              break;
  160.           case '$':
  161.              store(EOL);
  162.              break;
  163.           case '.':
  164.              store(ANY);
  165.              break;
  166.           case '[':
  167.              s = cclass(source, s);
  168.              break;
  169.           case ':':
  170.              if (*s)
  171.              {
  172.                 c = *s++;
  173.                 switch(tolower(c))
  174.                 {
  175.                     case 'a':
  176.                        store(ALPHA);
  177.                        break;
  178.                     case 'd':
  179.                        store(DIGIT);
  180.                        break;
  181.                     case 'n':
  182.                        store(NALPHA);
  183.                        break;
  184.                     case ' ':
  185.                        store(WHITE);
  186.                        break;
  187.                     default:
  188.                        badpat("Unknown : type", source, s);
  189.                 }
  190.                 break;
  191.              }
  192.              else
  193.                 badpat("No : type", source, s);
  194.          case '\\':
  195.             if (*s)
  196.                 c = *s++;
  197.          default:
  198.             store(CHAR);
  199.             store(iflag ? tolower(c) : c);
  200.       }
  201.    }
  202.    store(ENDPAT);
  203.    store('\0');
  204. }
  205.  
  206.  
  207. char *cclass(source, src)
  208. char *source;    /* ..Pattern start.. */
  209. char *src;      /* ..Class start.. */
  210. /* ..Compile a class (within []).. */
  211. {
  212.    register char   *s;        /* Source pointer    */
  213.    register char   *cp;       /* Pattern start     */
  214.    register int    c;         /* Current character */
  215.    int             o;                 /* ..Temp.. */
  216.  
  217.    s = src;
  218.    o = CLASS;
  219.    if (*s == '^')
  220.    {
  221.       ++s;
  222.       o = NCLASS;
  223.    }
  224.    store(o);
  225.    cp = pp;
  226.    store(0);                         /* ..Byte count.. */
  227.  
  228.    while ((c = *s++) && c!=']')
  229.    {
  230.       if (c == '\\')
  231.       {  /* ..Store quoted char.. */
  232.          if ((c = *s++) == '\0')     /* ..Gotta get something.. */
  233.              badpat("Class terminates badly", source, s);
  234.          else
  235.              store(iflag ? tolower(c) : c);
  236.       }
  237.       else if (c == '-' && (pp - cp) > 1 && *s != ']' && *s != '\0')
  238.       {
  239.          c = pp[-1];             /* Range start     */
  240.          pp[-1] = RANGE;         /* Range signal    */
  241.          store(c);               /* Re-store start  */
  242.          c = *s++;               /* Get end char and*/
  243.          store(iflag ? tolower(c) : c);
  244.       }
  245.       else
  246.          store(iflag ? tolower(c) : c);
  247.    }
  248.  
  249.    if (c != ']')
  250.       badpat("Unterminated class", source, s);
  251.    if ((c = (pp - cp)) >= 256)
  252.       badpat("Class too large", source, s);
  253.    if (c == 0)
  254.       badpat("Empty class", source, s);
  255.    *cp = c;
  256.    return(s);
  257. }
  258.  
  259.  
  260. store(op)
  261. {
  262.    if (pp >= &pbuf[PMAX])
  263.       error("Pattern too complex\n");
  264.    *pp++ = op;
  265. }
  266.  
  267.  
  268. badpat(message, source)
  269. char  *message,       /* ..Error message.. */
  270.       *source;        /* ..Pattern start.. */
  271. {
  272.    fprintf(stderr, "grep: %s, pattern is\"%s\"\n", message, source);
  273.    exit(1);
  274. }
  275.  
  276.  
  277.  
  278. grep(fn)
  279. char       *fn;       /* File name (for -f option)  */
  280. {
  281.    register int lno, count, m;
  282.  
  283.    lno = 0;
  284.    count = 0;
  285.    while (fgets(lbuf, LMAX, stdin))
  286.    {
  287.       ++lno;
  288.       m = match();
  289.       if ((m && !vflag) || (!m && vflag))
  290.       {
  291.           ++count;
  292.           if (!cflag)
  293.           {
  294.               if (lflag)
  295.               {
  296.                   puts(fn);
  297.                   return;
  298.               }
  299.               if (fflag && fn) 
  300.               {
  301.                   fprintf(stdout,"\n\nFile: %s\n\n",fn);
  302.                   fn = 0;
  303.               }
  304.               if (nflag)
  305.                  printf("%5d:  ", lno);
  306.               fputs(lbuf,stdout);
  307.           }
  308.       }
  309.    }
  310.    if (cflag)
  311.    {
  312.       if (fflag && fn)
  313.             printf("%-40.40s: ",trim_fspec(fn,40));
  314.       printf("%6d\n", count);
  315.    }
  316. }
  317.  
  318.  
  319. match()
  320. /* ..Match the current line (in lbuf[]), return 1 if it does.. */
  321. {
  322.    register char *l;        /* ..Line pointer.. */
  323.    char *pmatch();
  324.  
  325.    for (l = lbuf; *l; l++)
  326.       if (pmatch(l, pbuf))
  327.          return(1);
  328.  
  329.    return(0);
  330. }
  331.  
  332.  
  333. char *pmatch(line, pattern)
  334. char *line,     /* ..(partial) line to match.. */
  335.      *pattern;  /* ..(partial) pattern to match.. */
  336. {
  337.    register char   *l;        /* ..Current line pointer..